简述数据结构:二叉查找树
二叉查找树的性质
当一棵二叉树满足下面条件的时候就成了二叉查找树:对于树的任意一个节点,左儿子的值比右儿子小(或者反过来也行)。
二叉查找树本质还是二叉树,因此也具有二叉树的性质。
二叉查找树的操作
1. 判断某元素是否在树中:contains
这个操作比较简单,递归查找树根.
//公有函数contains通过调用私有函数contains递归查找。
bool contains(const Object &e) const
{
return contains(e, root);
}
bool contains(const Object &e, Node *t)
{
if(t == NULL)
return false;
if(e < t->element)
return contains(e, t->left);
else if(t->element < e)
return contains(e, t->right);
else
return true;
}
2. 插入一个元素:insert
往一个二叉查找树中插入元素不会改变原树的结构,只需要找到一个合适的位置满足二叉查找树的性质就可以了。
void insert(const Object &e)
{
insert(e, root);
}
//私有函数操作子树,二叉查找树的插入操作不会改变原树的结构
void insert(const Object &e, Node *&t)
{
//空子树
if(t == NULL)
{
t = new Node(e,NULL,NULL);
}
else
{
if(e < t->element)
insert(e, t->left);
else if(t->element < e)
insert(e, t->right);
else
;
}
}
3. 删除一个元素:remove
删除一个元素必须分情况来讨论。
- 要删除的节点是叶子。
如果要删除的节点是一个叶子,那么只需要简单地删除这个节点,并将其父节点的相关指针置为NULL就可以了,具体的做法是直接将这个节点的指针变为NULL,然后释放其存储。 - 要删除的节点只有一个子树。
如果要删除的节点只有一个子树,那么只需要让该节点的父节点指向节点的子树,然后释放掉该节点的存储。 - 要删除的节点有两个子树。
如果要删除的节点有两个子树,那么需要找出该节点右子树中的最小元素,并将这个最小元素赋给本节点,再将右子树中的该元素删除,此时的删除操作就转化成了1中情况(最小元素必为叶子)。
其中,上述1和2可以合并实现。
void remove(const Object &e)
{
remove(e, root);
}
void remove(const Object &e, Node *&t)
{
if(t == NULL)
return;
//未找到元素e,于是递归查找
if(e < t->element)
remove(e, t->left);
else if(t->element < e)
remove(e, t->right);
//找到元素e
else if(t->left != NULL && t->right != NULL) //有两个子节点
{
t->element = findMin(t->right);
remove(t->element, t->right);
}
else
{
Node *old = t;
t = (t->left != NULL)? t->left : t->right;
delete old;
}
}
二叉查找树C++实现
template <typename Object>
class BinarySearchTree
{
public:
BinarySearchTree():root(NULL){}
BinarySearchTree(BinarySearchTree &t)
{
root = t; //浅拷贝
}
~BinarySearchTree()
{
makeEmpty();
}
//深拷贝
BinarySearchTree & operator =(BinarySearchTree &t)
{
if(root == t)
return;
if(root != NULL)
makeEmpty();
root = clone(root);
}
void insert(const Object &e)
{
insert(e, root);
}
void remove(const Object &e)
{
remove(e, root);
}
bool contains(const Object &e) const
{
return contains(e, root);
}
bool isEmpty() const
{
return root == NULL;
}
const Object & findMin() const
{
return findMin(root);
}
const Object & findMax() const
{
return findMax(root);
}
void makeEmpty()
{
makeEmpty(root);
}
void printTree()
{
printTree(root);
std::cout<<"--------------"<<std::endl;
}
private:
struct Node
{
Object element;
Node *left;
Node *right;
Node(const Object &ele, Node *l, Node *r):element(ele),left(l),right(r){}
};
Node *root;
//私有函数操作子树,二叉查找树的插入操作不会改变原树的结构
void insert(const Object &e, Node *&t)
{
//空子树
if(t == NULL)
{
t = new Node(e,NULL,NULL);
}
else
{
if(e < t->element)
insert(e, t->left);
else if(t->element < e)
insert(e, t->right);
else
;
}
}
void remove(const Object &e, Node *&t)
{
if(t == NULL)
return;
//未找到元素e,于是递归查找
if(e < t->element)
remove(e, t->left);
else if(t->element < e)
remove(e, t->right);
//找到元素e
else if(t->left != NULL && t->right != NULL) //有两个子节点
{
t->element = findMin(t->right);
remove(t->element, t->right);
}
else
{
Node *old = t;
t = (t->left != NULL)? t->left : t->right;
delete old;
}
}
bool contains(const Object &e, Node *t)
{
if(t == NULL)
return false;
if(e < t->element)
return contains(e, t->left);
else if(t->element < e)
return contains(e, t->right);
else
return true;
}
const Object & findMin(Node *t) const
{
while(t->left != NULL)
{
t = t->left; //查找最左边的元素
}
return t->element;
}
const Object & findMax(Node *t) const
{
while(t->right != NULL)
{
t = t->right; //查找最右边的元素
}
return t->element;
}
void makeEmpty(Node * &t)
{
if(t != NULL)
{
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
t = NULL;
}
Node * clone(Node *t)
{
if(t == NULL)
return;
return new Node(t->element, t->left, t->right);
}
void printTree(const Node *t)
{
if(t == NULL)
return;
std::cout<<t->element<<std::endl;
if(t->left != NULL)
printTree(t->left);
if(t->right != NULL)
printTree(t->right);
}
};